package com.jhf.youke.gateway.config.filter;

import cn.hutool.json.JSONUtil;
import com.jhf.youke.core.entity.Message;
import com.jhf.youke.gateway.entity.BaseLog;
import com.jhf.youke.gateway.utils.MqUtils;
import org.reactivestreams.Publisher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.core.io.buffer.DataBuffer;

import java.nio.charset.Charset;
import java.util.Date;
import java.util.Map;


/**
 * @author RHJ
 */
public class RecorderServerHttpResponseDecorator extends ServerHttpResponseDecorator {

    private Logger logger = LoggerFactory.getLogger(RecorderServerHttpResponseDecorator.class);

    private BaseLog baseLog;

    RecorderServerHttpResponseDecorator(ServerHttpResponse delegate, BaseLog baseLog) {
        super(delegate);
        this.baseLog = baseLog;
//        this.filterService = filterService;
    }
    /**
     * 基于netty,我这里需要显示的释放一次dataBuffer,但是slice出来的byte是不需要释放的,
     * 与下层共享一个字符串缓冲池,gateway过滤器使用的是nettyWrite类,会发生response数据多次才能返回完全。
     * 在 ServerHttpResponseDecorator 之后会释放掉另外一个refCount.
     */
    @Override
    public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
        DataBufferFactory bufferFactory = this.bufferFactory();
        if (body instanceof Flux) {
            Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;
            Publisher<? extends DataBuffer> re = fluxBody.map(dataBuffer -> {
                // probably should reuse buffers
                byte[] content = new byte[dataBuffer.readableByteCount()];
                // 数据读入数组
                dataBuffer.read(content);
                // 释放掉内存
                DataBufferUtils.release(dataBuffer);
                // 记录返回值

                if(baseLog != null) {  //不需要记录操作日志的请求，baseLog为NULL
                    String s = new String(content, Charset.forName("UTF-8"));
                    baseLog.setAppendResponse(s);
                    baseLog.setUpdateTime(new Date());
                    try {
                        Integer negativeOne = -1;
                        String key = "code";
                        String code = "401";
                        Map<String, Object> map = JSONUtil.toBean(baseLog.getResultParam(), Map.class);
                        if (negativeOne.equals(map.get(key).toString()) || code.equals(map.get(key).toString())) {
                            baseLog.setStatus(1);
                        }
                    } catch (Exception e) {
                    }
                    try {
                        baseLog.setUpdateType(2);
                        Message message = new Message();
                        message.setTopic("baseLogConsume");
                        message.setTag("all");
                        message.setMessages(baseLog);
                        String data = JSONUtil.toJsonStr(MqUtils.send(message));
                        logger.info("更新操作日志：" + data);
                    } catch (Exception e) {
                        logger.error(e.getMessage());
                    }
                }
                return bufferFactory.wrap(content);
            });
            return super.writeWith(re);
        }
        return super.writeWith(body);
    }
    @Override
    public Mono<Void> writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) {
        return writeWith(Flux.from(body).flatMapSequential(p -> p));
    }
}
